package com.mattgarner.jaddas.node.command.ddl;

import java.util.HashMap;

import com.mattgarner.jaddas.dataset.DataSet;
import com.mattgarner.jaddas.dataset.DataSetPartition;
import com.mattgarner.jaddas.node.DataSetManager;
import com.mattgarner.jaddas.node.RemoteClient;
import com.mattgarner.jaddas.node.command.CommandParser;
import com.mattgarner.jaddas.node.data.TableException;
import com.mattgarner.jaddas.node.data.TableHeader;
import com.mattgarner.jaddas.node.net.Protocol;
import com.mattgarner.jaddas.node.net.Worker;

public class CmdCreateDataset extends CommandParser {

	public CmdCreateDataset(Worker serverWorker, RemoteClient client) {
		super(serverWorker, client);
	}
	
	public final boolean parseCommand(String command) {
		Worker worker = getServerWorker();
		RemoteClient clientConfig = getRemoteClient();
		
		command = command.replaceAll("\\s+?", " ");
		String[] cmd = extractRegexGroups("(?i)^CREATE\\s+DATASET\\s+([A-Z0-9_\\.]+?)\\s*(\"[A-Z0-9_ ].*?\")*\\s*\\((.*?)\\)\\s*$", command);
		
		String dsName;
		String dsDescription;
		String dsParameters;
		
		// validate arguments
		try { 
			dsName = cmd[0];
			dsDescription = cmd[1];
			if(dsDescription != null) { dsDescription = dsDescription.replaceAll("\"", ""); }
			dsParameters = cmd[2];
		} catch(RuntimeException e) {
			worker.sendMessage(Protocol.MSG_NAK, "Invalid parameters.");
			return true;
		}
		
		// check if dataset already exists
		DataSetManager dsManager = DataSetManager.getInstance();
		if(dsManager.getDataSetByName(dsName) != null) {
			worker.sendMessage(Protocol.MSG_NAK, "Dataset '" + dsName + "' already exists.");
			return true;
		}
		
		// check for prikey
		if(!dsParameters.contains("PRIKEY")) {
			worker.sendMessage(Protocol.MSG_NAK, "invalid parameters: Must contain a PRIKEY.");
			return true;
		}
		
		
		String[] fieldArgs = dsParameters.split("\\s*,\\s*");
		String[] colNames = new String[fieldArgs.length];
		String[] colFlags = new String[fieldArgs.length];
		HashMap<String, Boolean> colNameHash = new HashMap<String, Boolean>(fieldArgs.length);
		for(int a=0; a<fieldArgs.length; a++) {
			String[] args = extractRegexGroups("^\\s*(\\w+?)\\s+(.*?)\\s*$", fieldArgs[a]);
			String fieldName;
			String fieldFlags;
			try { 
				fieldName = args[0];
				fieldFlags = args[1].toUpperCase();
			} catch(RuntimeException e) {
				worker.sendMessage(Protocol.MSG_NAK, "Invalid field parameters at '" + fieldArgs[a] + "'");
				return true;
			}
			
			// check field type
			if((!fieldFlags.contains("VARCHAR")) && (!fieldFlags.contains("INT")) && (!fieldFlags.contains("LONG")) && (!fieldFlags.contains("SHORT")) && (!fieldFlags.contains("BINARY"))) {
				worker.sendMessage(Protocol.MSG_NAK, "Invalid field parameters at '" + fieldName + "': must specify INT, SHORT, LONG, VARCHAR or BINARY.");
				return true;
			}
			
			
			if(colNameHash.get(fieldName) != null) {
				worker.sendMessage(Protocol.MSG_NAK, "Duplicate field at '" + fieldName + "'.");
				return true;
			}
			
			
			colNames[a] = fieldName;
			colFlags[a] = fieldFlags;
			colNameHash.put(fieldName, true);
		}
		
		// now we have what we need to create a dataset
		// create table headers first
		
		TableHeader newDataHeader = new TableHeader(dsName+"_data");
		
		for(int b=0; b<colNames.length; b++) {
			try { 
				if(colFlags[b].contains("INT")) {
					newDataHeader.addIntColumn(colNames[b]);
				}
				if(colFlags[b].contains("SHORT")) {
					newDataHeader.addShortColumn(colNames[b]);
				}
				if(colFlags[b].contains("LONG")) {
					newDataHeader.addLongColumn(colNames[b]);
				}
				if(colFlags[b].contains("VARCHAR")) {
					newDataHeader.addVarcharColumn(colNames[b]);
				}
				if(colFlags[b].contains("BINARY")) {
					newDataHeader.addBinaryColumn(colNames[b]);
				}
				if(colFlags[b].contains("PRIKEY")) {
					newDataHeader.setPrimaryKey(b);
				}
				
				if(colFlags[b].contains("AUTOINCREMENT")) {
					newDataHeader.setAutoIncrementKey(b);
				}
				
			} catch(TableException e) {
				worker.sendMessage(Protocol.MSG_NAK, "Table creation error: " + e.getMessage());
				return true;
			}
		}
		
		int newDSID = dsManager.getNextDataSetID();
		DataSet newDataSet = new DataSet(newDSID, dsName, dsDescription, newDataHeader);
		dsManager.addDataSet(newDataSet);
		
		// create new default partition
		DataSetPartition dsPartition = new DataSetPartition(newDataSet, 0, true);
		dsManager.saveDataSetPartitionToDisk(dsPartition);
		newDataSet.registerPartition(dsPartition);
		
		
		worker.sendMessage(Protocol.MSG_OK, "DataSet '"+dsName+"' successfully added. (in "+calculateExecuteTime()+" secs.)");
		return true;

	}
}
